public class Method {
    //方法的定义
    public static boolean isLeapYear(int year){
        if((0==year%4 && 0!=year%100)||0==year%400){
            //普通闰年和世纪闰年
            return true;
        }else{
            return false;
        }
    }

    //计算1-5的阶乘
    public static int fac(int n){
        System.out.println("计算五的阶乘中n！="+n);
        int result=1;
        //
        for(int i=1;i<=n;i++){
            result*=i;
        }
        return result;
    }
    //交换两个整形变量
    //此时就需要传引用
    public static void swap(int x,int y){
        int tmp=x;
        x=y;
        y=tmp;
        System.out.println("swap:x="+x+"y="+y);
    }
    //形参只是实参的一份临时拷贝
    //形参改变并不会影响实参
    //对于基础类型来说，-传值调用
    public static void swap(int[]arr){
        int tmp=arr[0];
        arr[0]=arr[1];
        arr[1]=tmp;
    }
    public static double add(double x,double y){
        return x+y;
    }
    public static int add(int x,int y){
        System.out.println("调用方法中x="+x+"y="+y);
        return x+y;
    }
    public static float add(float x,float y){
        return x+y;
    }
    //java 中的重载，函数名相同，参数列表不同
    //就可以被称呼为方法了，和返回值无关

    //在同一个作用域中不能定义两个相同名称的标识符，比如方法中不能定义两个名字一样的变量
    //那为什么类中就可以定义方法名相同的方法呢？
    //方法签名：就是经过编译器修改过后方法最终的名字
    //具体形式：方法全路径名+参数列表+返回值类型

    // extend01/TestMethod.add:(DD)D
    //V:void
    //Z:boolean
    //B:byte
    //C:char
    //S:short
    //I:int
    //j:long
    //F:float
    //D:double
    //[:数组（可以配合其他的特殊字符，表述对应数据类型的数组，几个（就是几维的数组））
    //L：引用各类型，以L开头，以；结尾，中间是引用类型的全类名

    //递归求n的阶乘
    public static int factor(int n){
        if(n==1){
            return 1;
        }
        return n*factor(n-1);
        //factor函数调用函数自身
    }
    //按顺序打印数字的每一位
    public static void print(int num){
        if(num>9){
            print(num/10);
        }
        System.out.print(num%10+" ");
    }

    //递归求1+2+3+  10
    public static int sum(int num){
        if(num==1){
            return 1;
        }
        return num+sum(num-1);
    }
    //求一个非负整数组成它的数字之和
    public static int sum2(int num){
        if(num<10){
            return num;
        }
        return num%10+sum2(num/10);
    }
    //求斐波那契数列的第n项
    public static int fib(int n){
        if(n==1||n==2){
            return 1;
        }
        if (n == 3) {
            count++;
        }
        return fib(n-2)+fib(n-1);
    }
    public static int fib2(int num){
        int last2=1;
        int last1=1;
        int cur=0;
        for(int i=3;i<=num;i++){
            cur=last1+last2;//中间商来起到交换作用
            last2=last1;
            last1=cur;
        }
        return cur;
    }

    //什么是数组？？？
    //数组可以看作是相同类型的元素的集合
    //在内存中是一段连续的空间
    //每个空间有自己的编号，起始位置的编号为0，也就是数组的下标
    //那么在程序中如何创建数组呢？？

    int[] array=new int[100];
    //java中的数组理解看起来更加的合情合理，数组是一个类型
    //所以将int【】放在一起，以此来展示他是类型
    //因为数组是引用类型，想要获得一个实例化对象，必须要new
    //
    //数组的初始化

    //1.动态初始化
    //在创建数组时候，直接给出数组中元素的个数


    //2.静态初始化
    //在创建数组时候不直接给出数据元素的个数，而是直接将具体的内容进行指定
    //虽然没有直接指定数组的长度，但是编译器在编译的时候会自己数数的
    //具体是数据类型必须要与数组类型一直
    //静态初始化可以简写，省去了  new  T  【】


    //静态初始化也可以按照C语言中的方法创建
    //不过一般不推荐
    //

    //静态和动态初始化也可以分为两部




    public static void main(String[] args) {
        int[] array1;
        array1=new int [10];

        int[]array2;
        array2=new int[]{1,2,3,4,5,6,7,8};

        System.out.println(array2[0]);
        System.out.println(array2[1]);
        System.out.println(array2[2]);
        System.out.println(array2[3]);
        System.out.println(array2[4]);
        System.out.println(array2[5]);
        System.out.println(array2[6]);
        System.out.println(array2[7]);
        //通过观察代码可以发现，对数组中每个元素的操作都是相同的，则可以使用循环来打印
        //
        for (int i = 0; i < array2.length; i++) {
            System.out.print(array2[i]+" ");
        }
        //数组对象.length
        //使用foreach
        for (int x:array2
             ) {
            System.out.print(array2[x]+" ");
            //使用这个东西，可以完成堆数组的遍历，但是却无法使用具体的i，去控制某一个的变化
        }

//初始jvm的内存分布
        //1.程序运行时，需要代码加载到内存
        //程序运行时产生的中间数据也要存放在内存
        //程序中的常量也要存放在内存
        //有些数据可能需要长时间存储，而有些数据当方法运行完就要被销毁
        //如果对内存中的数据不加区分的随意存储，那么堆内存管理起来就会非常的麻烦
        //

        //所以jvm就堆所用的内存按照功能进行了不同的划分
        //线程共享：方法区、堆

        //线程隔离：虚拟机栈、本地方法栈、程序计数器
        //

        //程序计数器：pc：只是一个很小的空间，用来存放下一条执行指令的代码
        //虚拟机栈：与一些方法调用有关的信息，在每个方法执行时，都会先创建一个栈帧，栈帧中包含有
        //：局部变量表，操作数栈，动态链接，返回地址以及一些其他的信息，保存的都是与方法执行时相关的一些基本的信息
        //比如局部变量，当方法运行结束后，栈帧就被销毁了，栈帧里面保存的数据也被销毁了。
        //本地方法栈：与虚拟机方法栈类似，只不过保存的是Native方法的局部变量，在游戏版本的jvm实现中（HotSpot），本地方法栈与虚拟机栈是一起的
        //堆：jvm所管理的最大内存区域，使用new关键词创建的对象都是在堆上保存，堆是随着程序开始运行时而创建，随着程序的退出而销毁
        //堆中的数据只要还有在使用，就不会被销毁
        //方法区：用于存储已被虚拟机加载的类信息，常量，静态变量，即时编译器编译后的代码等数据，方法编译出的字节码就是保存在这个区域

        //基本类型变量和引用类型变量的区别
        //存值和存地址的区别，
        //引用其实是对指针的一种封装
        //引用存的是对象在堆空间中的起始地址
        //通过该地址，应用变量便可以去操作对象
        //null：空引用，不指向对象的引用
        //








        //注意省略格式不可以拆分，否则编译失败
        //如果没有堆数组初始化，数组中元素有其默认值
        //基本类型---也就是基本类型对应的0值

        //引用类型，默认存储的是null
        //

        //数组的使用
        //数组之中元素的访问
        //数组通过下标去访问任意位置的元素
        //数组是一段连续的内存空间，因此支持随机访问
        //即通过下标访问快速访问数组中任意位置的元素
        //下标从零开始
        //左闭右开--大多都遵循
        //遍历数组
        //
    }

    //可以使用循环的方式来求斐波那契数列，避免出现冗余运算
    public static int count=0;
    //这个是类的成员变量
    public static void main7(String[] args) {
        System.out.println(fib(40));
        System.out.println((count));
    }
    public static void main6(String[] args) {
        System.out.println(fib(10));
        System.out.println(sum2(1234));
        System.out.println(sum(10));
        System.out.println("=============");
        print(1234);
    }
    public static void main5(String[] args) {
        int n=5;
        int ret=factor(n);
        System.out.println("ret="+ret);
    }
    public static void main4(String[] args) {
        System.out.println(add(2,3));
        System.out.println(add(2.5f,3.5f));;
        System.out.println(add(2.5,3.5));;
        ;
//编译器在编译代码的时候，会对实参类型进行推演
        //根据推演过的结果决定来调用哪一个
        int[]arr={10,20};
        swap(arr);
        System.out.println("arr[0]="+arr[0]+"arr[1]"+arr[1]);
    }

    public static void main3(String[] args) {
        int a=10;
        int b=20;
        swap(a,b);
        System.out.println("main:a="+a+"b="+b);
    }
    public static void main2(String[] args) {
        boolean tmp=isLeapYear(2000);
        System.out.println(tmp);
        System.out.println("==================");
        System.out.println(add(3,9));
        System.out.println("==================");
        int a=10;
        int b=20;
        System.out.println("第一次调用方法之前");
        int ret=add(a,b);
        System.out.println("第一次调用方法之后");
        System.out.println("ret="+ret);

        System.out.println("第二次方法调用之前");
        ret=add(300,600);
        System.out.println("第二次方法调用之后");
        System.out.println("ret="+ret);
        System.out.println("===============");
        int sum=0;
        for(int i=1;i<=5;i++){
            sum+=fac(i);
        }
        System.out.println("sum="+sum);

        //使用方法要避免使用二重循环，让代码更加的简洁清晰

    }
}
